//
//  YHNetwork.swift
//  YHKit
//
//  Created by amovision on 2025/8/5.
//

import Foundation

// MARK: - 环境配置

enum Environment {
  case development
  case testing
  case production
    
  var baseURL: String {
    switch self {
    case .development: "https://dev.api.example.com"
    case .testing: "https://test.api.example.com"
    case .production: "https://api.example.com"
    }
  }
}

// MARK: - 错误类型定义

enum NetworkError: Error {
  case invalidURL
  case invalidRequest
  case networkError(Error)
  case invalidResponse
  case statusCode(Int)
  case jsonParsingFailed(Error)
  case missingRequiredField(String)
  case invalidDataFormat
}

// MARK: - API参数模型

struct LoginParams: Encodable {
  let username: String
  let password: String
}

struct UpdateUserInfoParams: Encodable {
  let name: String?
  let avatar: String?
  let age: Int?
}

// MARK: - API定义

enum NetworkAPI {
  case login(LoginParams)
  case logout
  case userInfo
  case updateUserInfo(UpdateUserInfoParams)
    
  // 服务器地址，可根据环境动态切换
  var baseURL: String {
    // 实际项目中可根据配置动态切换环境
    Environment.production.baseURL
  }
    
  // 接口路径
  var path: String {
    switch self {
    case .login: "/login"
    case .logout: "/logout"
    case .userInfo: "/userInfo"
    case .updateUserInfo: "/updateUserInfo"
    }
  }
    
  // 请求方法
  var method: HTTPMethod {
    switch self {
    case .login, .updateUserInfo: .post
    default: .get
    }
  }
    
  // 请求参数
  var parameters: Encodable? {
    switch self {
    case .login(let params): params
    case .updateUserInfo(let params): params
    default: nil
    }
  }
    
  // 超时时间
  var timeoutInterval: TimeInterval { 15 }
    
  // 请求头
  var headers: [String: String] {
    var headers = ["Content-Type": "application/json"]
    // 可添加通用头信息，如Token等
    if let token = AuthManager.shared.token {
      headers["Authorization"] = "Bearer \(token)"
    }
    return headers
  }
    
  // 构建URLRequest
  var urlRequest: Result<URLRequest, NetworkError> {
    // 构建URL
    guard let baseURL = URL(string: baseURL),
          let url = URL(string: path, relativeTo: baseURL)?.absoluteURL
    else {
      return .failure(.invalidURL)
    }
        
    var request = URLRequest(url: url)
    request.httpMethod = method.rawValue
    request.timeoutInterval = timeoutInterval
    headers.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
        
    // 设置请求体（仅非GET请求）
    if method != .get, let parameters = parameters {
      do {
        request.httpBody = try JSONEncoder().encode(parameters)
      } catch {
        return .failure(.jsonParsingFailed(error))
      }
    }
        
    return .success(request)
  }
}

// MARK: - HTTP方法枚举

enum HTTPMethod: String {
  case get = "GET"
  case post = "POST"
  case put = "PUT"
  case delete = "DELETE"
}

// MARK: - 网络请求结果

struct NetworkResult<T: Codable>: Codable {
  let code: Int
  let message: String
  let data: T?
    
  // 状态判断
  var isSuccess: Bool { code == 200 }
  var isLoginInvalid: Bool { code == 401 || code == 402 }
    
  // 解析JSON数据
  static func parse(from data: Data) -> Result<NetworkResult<T>, NetworkError> {
    do {
      let decoder = JSONDecoder()
      decoder.keyDecodingStrategy = .convertFromSnakeCase
      let result = try decoder.decode(NetworkResult<T>.self, from: data)
      return .success(result)
    } catch {
      return .failure(.jsonParsingFailed(error))
    }
  }
}

// MARK: - 拦截器协议

protocol RequestInterceptor {
  func adapt(_ request: URLRequest) -> URLRequest
}

protocol ResponseInterceptor {
  func handle<T: Codable>(_ result: Result<NetworkResult<T>, NetworkError>) -> Result<NetworkResult<T>, NetworkError>
}

// MARK: - 认证管理

class AuthManager {
  static let shared = AuthManager()
  var token: String?
  var isRefreshingToken = false
  var pendingRequests: [(URLRequest) -> Void] = []
}

// MARK: - 默认拦截器实现

class DefaultInterceptor: RequestInterceptor, ResponseInterceptor {
  func adapt(_ request: URLRequest) -> URLRequest {
    // 可以在这里统一添加认证信息等
    var request = request
    // 示例：添加设备信息
    request.setValue("iphone12,1", forHTTPHeaderField: "Device-Model")
    return request
  }
    
  func handle<T: Codable>(_ result: Result<NetworkResult<T>, NetworkError>) -> Result<NetworkResult<T>, NetworkError> {
    // 统一处理响应，如Token过期等
    switch result {
    case .success(let networkResult) where networkResult.isLoginInvalid:
      // 处理登录失效，如跳转登录页
      AuthManager.shared.token = nil
      NotificationCenter.default.post(name: NSNotification.Name("LoginInvalid"), object: nil)
      return .failure(.invalidResponse)
    default:
      return result
    }
  }
}

// MARK: - 网络请求协议

protocol NetworkClientProtocol {
  func request<T: Codable>(
    api: NetworkAPI,
    callbackQueue: DispatchQueue,
    completion: @escaping (Result<NetworkResult<T>, NetworkError>) -> Void
  ) -> URLSessionTask?
    
  func cancelAllTasks()
}

// MARK: - 网络请求管理类

final class NetworkClient: NetworkClientProtocol {
  static let shared = NetworkClient()
  private let session: URLSession
  private let requestInterceptor: RequestInterceptor
  private let responseInterceptor: ResponseInterceptor
  private var tasks: [Int: URLSessionTask] = [:]
    
  // 初始化
  init(
    session: URLSession = .shared,
    requestInterceptor: RequestInterceptor = DefaultInterceptor(),
    responseInterceptor: ResponseInterceptor = DefaultInterceptor()
  ) {
    self.session = session
    self.requestInterceptor = requestInterceptor
    self.responseInterceptor = responseInterceptor
  }
    
  // 发起请求
  func request<T: Codable>(
    api: NetworkAPI,
    callbackQueue: DispatchQueue = .main,
    completion: @escaping (Result<NetworkResult<T>, NetworkError>) -> Void
  ) -> URLSessionTask? {
    // 构建请求
    guard case .success(var request) = api.urlRequest else {
      callbackQueue.async { completion(.failure(.invalidRequest)) }
      return nil
    }
        
    // 请求拦截
    request = requestInterceptor.adapt(request)
        
    // 打印请求日志（仅DEBUG模式）
    #if DEBUG
    print("==============REQUEST_START==============")
    print("[URL]: \(request.url?.absoluteString ?? "Invalid URL")")
    print("[Method]: \(request.httpMethod ?? "GET")")
    if let headers = request.allHTTPHeaderFields {
      print("[Headers]: \(headers)")
    }
    if let body = request.httpBody, let bodyStr = String(data: body, encoding: .utf8) {
      print("[Body]: \(bodyStr)")
    }
    print("===============REQUEST_END===============")
    #endif
        
    // 创建任务
    var task: URLSessionTask? = nil
    task = session.dataTask(with: request) { [weak self] data, response, error in
      guard let self = self else { return }
            
      // 从任务列表移除
      updateTask(task: task, isAdd: false)
            
      // 处理错误
      if let error = error {
        callbackQueue.async {
          completion(.failure(.networkError(error)))
        }
        return
      }
            
      // 验证响应
      guard let httpResponse = response as? HTTPURLResponse else {
        callbackQueue.async { completion(.failure(.invalidResponse)) }
        return
      }
            
      // 检查状态码
      guard 200 ..< 300 ~= httpResponse.statusCode else {
        callbackQueue.async { completion(.failure(.statusCode(httpResponse.statusCode))) }
        return
      }
            
      // 验证数据
      guard let data = data else {
        callbackQueue.async { completion(.failure(.invalidDataFormat)) }
        return
      }
            
      // 打印响应日志（仅DEBUG模式）
      #if DEBUG
      print("==============RESPONSE_START==============")
      print("[URL]: \(request.url?.absoluteString ?? "Invalid URL")")
      print("[Status Code]: \(httpResponse.statusCode)")
      if let responseStr = String(data: data, encoding: .utf8) {
        print("[Response]: \(responseStr)")
      }
      print("===============RESPONSE_END===============")
      #endif
            
      // 解析数据
      let result = NetworkResult<T>.parse(from: data)
      let handledResult = self.responseInterceptor.handle(result)
            
      callbackQueue.async {
        completion(handledResult)
      }
    }
        
    // 添加到任务列表并启动
    updateTask(task: task, isAdd: true)
    task?.resume()
        
    return task
  }
  
  private func updateTask(task: URLSessionTask?, isAdd: Bool) {
      guard let task else { return }
    if isAdd { tasks[task.taskIdentifier] = task }
      else { tasks.removeValue(forKey: task.taskIdentifier) }
  }
  
    
  // 取消所有任务
  func cancelAllTasks() {
    tasks.values.forEach { $0.cancel() }
    tasks.removeAll()
  }
}
